package com.studio5704website.api;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.studio5704website.api.exception.InvalidRequestException;
import com.studio5704website.api.exception.UserNotFoundException;
import com.studio5704website.application.UserQueryService;
import com.studio5704website.application.data.RoleWithToken;
import com.studio5704website.application.data.UserData;
import com.studio5704website.core.httpResult.HttpResult;
import com.studio5704website.core.service.JwtService;
import com.studio5704website.core.user.EncryptService;
import com.studio5704website.core.user.RoleWithTokenService;
import com.studio5704website.core.user.User;
import com.studio5704website.core.user.UserRepository;
import com.studio5704website.infrastructure.service.RedisUtil;
import io.swagger.annotations.*;
import lombok.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.util.Optional;


/**
 * @author 高威
 * 登录Api
 */
@RestController
@Api(tags = {"用户接口"})
public class UserApi {
    private EncryptService encryptService;
    private UserRepository userRepository;
    private String defaultImage;
    private UserQueryService userQueryService;
    private JwtService jwtService;
    private String permission;
    private RedisUtil redisUtil;
    private long overDueTime;
    private RoleWithTokenService roleWithTokenService;

    @Autowired
    public UserApi(UserRepository userRepository,
                   EncryptService encryptService,
                   @Value("${image}") String defaultImage,
                   UserQueryService userQueryService,
                   @Qualifier("cusJwtService")
                   JwtService jwtService,
                   @Value("${default-permission}") String permission,
                   RedisUtil redisUtil,
                   @Value("${tokenOverdueTime}") long overDueTime,
                   @Qualifier("redisRoleWithTokenService") RoleWithTokenService roleWithTokenService) {
        this.encryptService = encryptService;
        this.userRepository = userRepository;
        this.defaultImage = defaultImage;
        this.userQueryService = userQueryService;
        this.jwtService = jwtService;
        this.permission = permission;
        this.redisUtil = redisUtil;
        this.overDueTime = overDueTime;
        this.roleWithTokenService = roleWithTokenService;
    }

    @RequestMapping(value = "user/login", method = RequestMethod.POST)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "登录成功", response = HttpResult.class),
            @ApiResponse(code = 400, message = "登录参数错误", response = HttpResult.class),
            @ApiResponse(code = 401, message = "用户名或密码错误", response = HttpResult.class)
    })
    public ResponseEntity<?> login(@Valid @RequestBody @ApiParam(name = "登录参数", value = "传入用户JSON", required = true)
                                               LoginParam loginParam, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .bindingResult(bindingResult)
                    .statusCode(400)
                    .data(loginParam)
                    .build();
            throw new InvalidRequestException(result);
        }
        Optional<User> optional = userRepository.findByEmail(loginParam.getEmail());
        if (optional.isPresent() && encryptService.check(optional.get().getPassword(), loginParam.getPassword())) {
            User user = optional.get();
            UserData userData = userQueryService.findById(user.getId());
            // 这里将token信息写入redis, 并设置过期时间
            String token = jwtService.toToken(user);
            RoleWithToken roleWithToken = new RoleWithToken(user.getId(), token, user.getPermission(), overDueTime);
            roleWithTokenService.setRoleWithToken(roleWithToken);
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .statusCode(200)
                    .data(userData)
                    .message("请求成功")
                    .token(token)
                    .build();
            return ResponseEntity.ok().body(result);
        } else {
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .data(loginParam)
                    .message("用户名或密码错误")
                    .statusCode(401)
                    .build();
            throw new InvalidRequestException(result);
        }
    }

    @RequestMapping(value = "user/logout/{username}", method = RequestMethod.GET)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "登出成功", response = HttpResult.class),
            @ApiResponse(code = 404, message = "没有找到用户", response = HttpResult.class)
    })
    public ResponseEntity<?> logout(@ApiParam(name = "username", value = "用户名字", required = true)
                                        @PathVariable("username") String username) {
        Optional<User> user = userRepository.findByUsername(username);
        if (user.isPresent()) {
            roleWithTokenService.deleteLoginRole(user.get().getId());
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .message("登出成功！")
                    .statusCode(200)
                    .data(username)
                    .build();
            return ResponseEntity.ok().body(result);
        }
        throw new UserNotFoundException();
    }

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "注册成功, 返回用户信息", response = HttpResult.class),
            @ApiResponse(code = 400, message = "注册失败, 用户信息有误", response = HttpResult.class)
    })
    public ResponseEntity<?> createUser(@Valid @RequestBody @ApiParam(name = "注册用户参数", value = "用户JSON", required = true)
                                                    RegisterParam registerParam, BindingResult bindingResult) {
        checkInput(registerParam, bindingResult);
        User user = new User(
                registerParam.getEmail(),
                registerParam.getUsername(),
                encryptService.encrypt(registerParam.getPassword()),
                defaultImage,
                permission
        );
        userRepository.save(user);
        UserData userData = userQueryService.findById(user.getId());
        String token = jwtService.toToken(user);
        RoleWithToken roleWithToken = new RoleWithToken(user.getId(), token, permission, overDueTime);
        roleWithTokenService.setRoleWithToken(roleWithToken);
        HttpResult result = new HttpResult.HttpResultBuilder()
                .statusCode(200)
                .message("请求成功")
                .token(token)
                .data(userData)
                .build();
        return ResponseEntity.status(200).body(result);
    }

    private void checkInput(@Valid @RequestBody RegisterParam registerParam, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .data(registerParam)
                    .bindingResult(bindingResult)
                    .build();
            throw new InvalidRequestException(result);
        }
        if (userRepository.findByUsername(registerParam.getUsername()).isPresent()) {
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .statusCode(400)
                    .message("用户名重复！")
                    .data(registerParam)
                    .build();
            throw new InvalidRequestException(result);
        }

        if (userRepository.findByEmail(registerParam.getEmail()).isPresent()) {
            HttpResult result = new HttpResult.HttpResultBuilder()
                    .statusCode(400)
                    .message("邮箱重复！")
                    .data(registerParam)
                    .build();
            throw new InvalidRequestException(result);
        }
    }

}

@Data
class RegisterParam {
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式错误")
    @JsonProperty(value = "email")
    private String email;
    @NotBlank(message = "用户名不能为空")
    @JsonProperty(value = "username")
    private String username;
    @NotBlank(message = "密码不能为空")
    @JsonProperty(value = "password")
    private String password;
}

@Data
class LoginParam {
    @NotBlank(message = "邮箱不能为空")
    private String email;
    @NotBlank(message = "密码不能为空")
    private String password;
}
